package com.tfjybj.itoo.teach.provider.service.impl;

import org.apache.dubbo.config.annotation.Reference;;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.dmsdbj.itoo.authorizationManagement.entity.OrganizationEntity;
import com.dmsdbj.itoo.authorizationManagement.facade.OrganizationFacade;
import com.dmsdbj.itoo.tool.base.service.impl.BaseServicePlusImpl;
import com.dmsdbj.itoo.tool.business.ItooResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tfjybj.itoo.teach.entity.ClassEntity;
import com.tfjybj.itoo.teach.model.ClassModel;
import com.tfjybj.itoo.teach.provider.dao.ClassDao;
import com.tfjybj.itoo.teach.provider.service.ClassService;
import com.tfjybj.itoo.teach.provider.service.ProfessionService;
import com.tfjybj.itoo.teach.template.ClassInfoExportTemplate;
import com.tfjybj.itoo.teach.template.ClassInfoTemplate;
import lombok.extern.slf4j.Slf4j;
import org.jplus.hyberbin.excel.utils.ExcelUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.*;

import static com.tfjybj.itoo.teach.provider.until.DemoConstants.*;

/**
 * ClassService接口实现类
 * ${base}表
 *
 * @author 田成荣
 * @version 2.0.0
 * @since 2.0.0 2018-11-08 19:34:10
 */
@Service("classService")
@Slf4j
public class ClassServiceImpl extends BaseServicePlusImpl<ClassDao,ClassEntity> implements ClassService {
    private static final Logger logger = LoggerFactory.getLogger(ClassServiceImpl.class);

    @Resource
    private ClassService classService;

    @Resource
    private ProfessionService professionService;

    @Resource
    private RedisTemplate<String, ClassInfoTemplate> redisTemplate;

    //@Autowired(required = false)
    //private OrganizationFacade organizationFacade;

	//region 模板生成
    @Resource
    private ClassDao classDao;

    /**
     * 根据行政班名称模糊查询class
     *
     * @param name  行政班名称
     * @param pageNum   页码
     * @param pageSize 页数
     * @return 模糊查询的class
     * @author 田成荣
     * @since 2.0.0 2018-11-08 19:34:10
     */
    @Override
    public PageInfo<ClassEntity> queryByLikeName(String name, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo<>(classDao.queryLikeName(name));
    }
	//endregion

    /* **********************************以下为非模板生成的内容********************************* */
    /**
     * 根据专业id查询班级信息集合（带分页）
     * @param professionId
     * @param pageNo
     * @param pageSize
     * @return 该专业下所有班级
     * @author 杨燕梅
     * @since 2.0.0 2018-11-13 19:30:40
     */
    @Override
    public PageInfo<ClassModel>queryByProfessionIdPageInfo(String professionId,Integer pageNo, Integer pageSize) {
        PageHelper.startPage(pageNo,pageSize);
        return new PageInfo<>(classDao.queryByProfessionId(professionId));
    }

    /**
     * 根据专业id查询班级信息集合
     * @param professionId
     * @return 该专业下所有班级
     * @author 杨燕梅
     * @since 2.0.0 2018-11-18 09:00:16
     */
    @Override
    public List<ClassModel>queryByProfessionId(String professionId) {
        return classDao.queryByProfessionId(professionId);
    }

    /**
     * 根据专业id集合查询班级信息集合
     * @param professionIds
     * @return 专业id集合下属所有班级信息集合
     * @author 杨燕梅
     * @since 2.0.0 2018-11-13 19:35:31
     */
    @Override
    public List<ClassModel>queryByProfessionIds(List<String> professionIds){
        return classDao.queryByProfessionIds(professionIds);
    }

    /**
     *根据行政班id查询专业id
     * @param classId 行政班id集合
     * @return 行政班id
     * @author 田成荣
     * @since 2.0.0 2018-11-13 19:07:35
     */
    @Override
    public String queryProfessionIdByClassId(String classId){
        return classDao.queryProfessionIdByClassId(classId);
    }

    /**
     * 根据年级查询班级信息
     * @author 杨燕梅
     * @since 2.0.0 2018-11-24 15:32:34
     */
    @Override
    public List<ClassModel> queryClassByGrade(String grade) {
        return classDao.queryClassByGrade(grade);
    }

    /**
     * 根据专业id和年级查询班级信息
     * @author 杨燕梅
     * @since 2.0.0 2018-11-24 21:19:24
     */
    @Override
    public List<ClassModel> queryClassByProfessionIdAndGrade(String professionId,String grade) {
        return classDao.queryClassByProfessionIdAndGrade(professionId,grade);
    }

    /**
     * 根据行政班code 查询班级信息
     * @param code
     * @return
     * @author 严文文
     * @since 2.0.0 2018-11-27 10:35:34
     */
    @Override
    public List<ClassModel> queryClassesByCode(String code){
        return classDao.queryClassesByCode(code);
    }

    /**
     * 根据班级名称模糊查询某一专业下属班级
     *
     * @param professionId 专业id
     * @param searchContent  行政班名称
     * @param pageNum   页码
     * @param pageSize 页数
     * @return 模糊查询的class
     * @author 杨燕梅
     * @since 2.0.0 2018-11-29 10:36:13
     */
    @Override
    public PageInfo<ClassModel> queryByLikeNameAndProfessionId(String professionId, Integer pageNum, Integer pageSize,String searchContent) {
        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo<>(classDao.queryByLikeNameAndProfessionId(professionId,searchContent.trim()));
    }

    /**
     * 根据班级ID查询班级详情
     *
     * @param idList 班级ID
     * @return 班级实体集合
     * @author 杨燕梅
     * @since 2.0.0 2018-12-12 21:29:18
     */
    @Override
    public List<ClassModel> queryClassById(List<String> idList) {
        return classDao.queryClassById(idList);
    }

    /**
     * 根据ID导出班级信息
     *
     * @param response 响应
     * @param idList   班级ID
     * @return 导出结果信息
     * @author 杨燕梅
     * @since 2.0.0 2018-12-12 21:29:22
     */
    @Override
    public ItooResult exportByClassId(HttpServletResponse response, List<String> idList) {
        Map<Serializable, Serializable> map = new HashMap<>(16);

        map.put(SHEET_NAME, "导出的班级信息");
        //要导出的字段
        map.put(COLUMNS,  new String[]{"code", "name", "professionName", "grade", "remark"});
        //导出表格的标题
        map.put(TITLE, "导出的班级信息");
        map.put(NAME, "导出的班级信息");
        //要导出的数据
        List<ClassInfoExportTemplate> classInfoExportTemplateList = new ArrayList<>();

        List<ClassModel> classModelList = classDao.queryClassById(idList);
        for (ClassModel classModel : classModelList) {
            ClassInfoExportTemplate classInfoExportTemplate = new ClassInfoExportTemplate();
            BeanUtils.copyProperties(classModel, classInfoExportTemplate);
            classInfoExportTemplateList.add(classInfoExportTemplate);
        }
        //为空不进行导出
        if (CollectionUtils.isEmpty(classInfoExportTemplateList)) {
            return ItooResult.build(ItooResult.FAIL, "没有要导出的数据！");
        }
        map.put(DATA_LIST, (Serializable) classInfoExportTemplateList);

        //导出
        try {
            ExcelUtil.exportExcel(map, response);
        } catch (Exception e) {
            log.error("导出失败,未知的异常--" + e);
            return ItooResult.build(ItooResult.FAIL, "导出信息失败！", e);
        }
        return ItooResult.build(ItooResult.SUCCESS, "导出信息成功！");
    }

    /**
     * 根据条件导出班级
     *
     * @param response     响应
     * @param searchContent    班级名称/班级简称
     * @return 导出结果信息
     * @author 杨燕梅
     * @since 2.0.0 2018-12-23 17:54:38
     */
    @Override
    public ItooResult exportByStrLike(HttpServletResponse response, String professionId, String searchContent) {
        Map<Serializable, Serializable> map = new HashMap<>(16);
        map.put(SHEET_NAME, "班级");
        //要导出的字段
        map.put(COLUMNS,   new String[]{"code", "name", "professionName", "grade", "remark"});
        //导出表格的标题
        map.put(TITLE, "班级信息");
        map.put(NAME, "按条件导出的班级信息");
        //要导出的数据
        List<ClassInfoExportTemplate> classInfoExportTemplateList = new ArrayList<>();
        List<ClassModel> classModelList = classDao.queryByLikeNameAndProfessionId(professionId ,searchContent);
        for (ClassModel classModel : classModelList) {
            ClassInfoExportTemplate classInfoExportTemplate = new ClassInfoExportTemplate();
            BeanUtils.copyProperties(classModel, classInfoExportTemplate);
            classInfoExportTemplateList.add(classInfoExportTemplate);
        }
        //为空不进行导出
        if (CollectionUtils.isEmpty(classInfoExportTemplateList)) {
            return ItooResult.build(ItooResult.FAIL, "没有要导出的数据！");
        }
        map.put(DATA_LIST, (Serializable) classInfoExportTemplateList);

        //导出
        try {
            ExcelUtil.exportExcel(map, response);
        } catch (Exception e) {
            log.error("导出失败,未知的异常--" + e);
            return ItooResult.build(ItooResult.FAIL, "导出信息失败！", e);
        }
        return ItooResult.build(ItooResult.SUCCESS, "导出信息成功！");
    }

    /**
     * 下载班级模板，批量导入使用
     *
     * @param response 响应
     * @return 下载模板是否成功
     * @author 杨燕梅
     * @since 2.0.0 2018-11-30 10:43:38
     */
    @Override
    public boolean downLoadTemplate(HttpServletResponse response) {
        Map<Serializable, Serializable> map = new HashMap<>(16);
        List<ClassInfoTemplate> templateList = new ArrayList<>();
        ClassInfoTemplate classInfoTemplate = new ClassInfoTemplate();
        classInfoTemplate.setCode("05044141");
        classInfoTemplate.setName("14级教育技术学1班");
        classInfoTemplate.setProfessionName("教育技术学");
        classInfoTemplate.setGrade("2014");
        classInfoTemplate.setRemark("导入数据模板");
        templateList.add(classInfoTemplate);
        //sheet的名字
        map.put(SHEET_NAME, "班级信息");
        //需要导入的字段
        map.put(COLUMNS,   new String[]{"code", "name", "professionName", "grade", "remark"});
        //表格的标题
        map.put(TITLE, "班级信息");
        map.put(NAME, "班级信息模板");
        map.put(DATA_LIST, (Serializable) templateList);
        try {
            ExcelUtil.exportExcel(map, response);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 批量导入班级
     * @param multipartFile
     * @param request
     * @param response
     * @return
     * @author 杨燕梅
     * @since 2.0.0 2018-12-2 11:43:13
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ItooResult importTemplate(MultipartFile multipartFile, HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("UTF-8");
        try {
            //校验文件是否存在
            String fileName = multipartFile.getOriginalFilename();
            if (fileName == null) {
                log.error("导入失败,fileName is null!");
                return ItooResult.build(ItooResult.FAIL, "传入的文件为空！");
            }
            //EXCEL解析成List
            Map<Serializable, Serializable> map = new HashMap<>(4);
            map.put(SHEET_NAME, "班级信息");
            map.put(CLASS, ClassInfoTemplate.class);
            List<ClassInfoTemplate> classInfoTemplateList = ExcelUtil.importExcel(Objects.requireNonNull(fileName), map, request, response);
            if (CollectionUtils.isEmpty(classInfoTemplateList)) {
                return ItooResult.build(ItooResult.FAIL, "导入的数据为空，请填写！");
            }
            //定义导入的错误数据集合并存redis中形式的<String,ClassInfoTemplate>
            List<ClassInfoTemplate> errorCTList = new ArrayList<>();
            String errorCTListId = IdWorker.getIdStr();
            Long size = redisTemplate.opsForZSet().size(errorCTListId);
            size = size == null ? 0L : size;
            //循环处理数据
            for (ClassInfoTemplate excelCT : classInfoTemplateList) {
                if (!this.verify(excelCT)) {
                    ClassInfoTemplate classInfoTemplate = new ClassInfoTemplate();
                    BeanUtils.copyProperties(excelCT, classInfoTemplate);
                    errorCTList.add(classInfoTemplate);
                    redisTemplate.opsForZSet().add(errorCTListId, classInfoTemplate, size + 1);
                    continue;
                }
                ClassEntity classEntity = new ClassEntity();
                //将导入内容放到entity中对应的属性中去
                BeanUtils.copyProperties(excelCT,classEntity);
                //班级编码
                classEntity.setCode(excelCT.getCode());
                //班级名称
                classEntity.setName(excelCT.getName());
                //年级
                classEntity.setGrade(excelCT.getGrade());
                //备注
                classEntity.setRemark(excelCT.getRemark());
                this.save(classEntity);
                this.saveToAuth(classEntity);
            }
            //不符合条件的信息返回
            if (!CollectionUtils.isEmpty(errorCTList)) {
                return ItooResult.build("0001", "部分导入失败", errorCTListId);
            }
        } catch (Exception e) {
            return ItooResult.build(ItooResult.FAIL, "导入数据异常！", e);
        }
        return ItooResult.build(ItooResult.SUCCESS, "导入数据成功！");
    }
    /**
     * 判断批量导入的信息是否符合要求
     *
     * @param classInfoTemplate 需要导入的信息
     * @return boolean 导入的字段是否为空
     * @author 杨燕梅
     * @since 2.0.0 2018-11-30 08:52:33
     */
    private boolean verify( ClassInfoTemplate classInfoTemplate) {
        //判断班级代码是否存在
        if (StringUtils.isEmpty(classInfoTemplate.getCode())) {
            classInfoTemplate.setFailReason("班级代码未填写");
            log.warn("导入失败,班级代码未填写,excelClassEntity-{}", classInfoTemplate);
            return false;
        }
        //判断班级名称是否存在
        if (StringUtils.isEmpty(classInfoTemplate.getName())) {
            classInfoTemplate.setFailReason("班级名称未填写");
            log.warn("导入失败,班级名称未填写,excelClassEntity-{}", classInfoTemplate);
            return false;
        }
        //判断年级是否存在
        if (StringUtils.isEmpty(classInfoTemplate.getGrade())) {
            classInfoTemplate.setFailReason("年级未填写");
            log.warn("导入失败,年级未填写,excelClassEntity-{}", classInfoTemplate);
            return false;
        }
        //判断班级是否重复
        if (!CollectionUtils.isEmpty(classDao.queryByCodeAndNameExist(classInfoTemplate.getCode(),classInfoTemplate.getName()))){
            classInfoTemplate.setFailReason("班级已存在");
            log.warn("导入失败,班级已存在,excelClassEntity-{}", classInfoTemplate);
            return false;
        }
        //判断专业id是否获取到
        String professionId = professionService.queryProfessionIdByName(classInfoTemplate.getProfessionName());
        if(StringUtils.isEmpty(professionId)){
            classInfoTemplate.setFailReason("专业不存在");
            log.warn("导入失败,专业不存在,excelClassEntity-{}", classInfoTemplate);
            return false;
        }
        classInfoTemplate.setProfessionId(professionId);
        return true;
    }

    /**
     * 根据errorListId导出未成功导入的班级信息
     *
     * @param response    响应
     * @param errorListId 为成功导入的分组id
     * @return 导出结果
     * @author 杨燕梅
     * @since 1.0.0 2018-12-1 19:39:17
     */
    @Override
    public boolean exportErrorList(String errorListId, HttpServletResponse response){
        //redis取出没有成功导入的班级信息
        Set set = redisTemplate.opsForZSet().range(errorListId, 0, -1);
        List<ClassInfoTemplate> classInfoTemplateList=new ArrayList<>(set);
        //清空redis数据
        redisTemplate.delete(errorListId);
        //导出没有成功导入的班级信息
        if(classInfoTemplateList.size()==0){
            return false;
        }
        Map<Serializable, Serializable> errorMap = new HashMap<>(16);
        errorMap.put(NAME, "未导入的班级信息");
        errorMap.put(SHEET_NAME, "未导入的班级信息");
        errorMap.put(TITLE, "未导入的班级信息");
        errorMap.put(COLUMNS, new String[]{"code", "name", "professionName", "grade", "remark", "failReason"});
        errorMap.put(DATA_LIST, (Serializable) classInfoTemplateList);
        try {
            ExcelUtil.exportExcel(errorMap, response);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 查询所有Class
     *
     * @since 2.0.0 2018-11-08 19:34:10
     */
    @Override
    public List<ClassEntity> queryAll(){
        return classDao.queryAll();
    }

    /**
     * 根据班级代码和班级名称查询班级是否已存在
     *
     * @param code   班级代码
     * @param name   班级名称
     * @return 班级信息
     * @author 杨燕梅
     * @since 2.0.0 2018-12-20 09:57:54
     */
    @Override
    public List<ClassEntity>queryByCodeAndNameExist(String code, String name){
        return classDao.queryByCodeAndNameExist(code,name);
    }

    /**
     * 将数据保存到权限中去
     *
     * @param classEntity
     * @author 李建帅
     * @since 2.0.0 2018-12-9 19:18:10
     */
    @Override
    public void saveToAuth(ClassEntity classEntity){
//        List<OrganizationEntity> organizationEntityList = new ArrayList<>();
//        OrganizationEntity organizationEntity = new OrganizationEntity();
//        organizationEntity.setId(classEntity.getId());
//        organizationEntity.setOrganizationName(classEntity.getName());
//        organizationEntity.setPId(classEntity.getProfessionId());
//        organizationEntity.setCompanyId("lfsfxy111222");
//        organizationEntityList.add(organizationEntity);
//        organizationFacade.synchroOrganization(organizationEntityList);
//
//        try {
//            organizationFacade.synchroOrganization(organizationEntityList);
//        } catch (Exception e) {
//            log.error("将组织机构信息同步到权限中心失败！", e);
//        }
    }

    /**
     * 根据professionId查找所有行政班信息
     *
     * @param professionId 专业id
     * @return classEntityList
     * @author 智雪艳
     * @since 2.0.0 2019-05-28 10:35:56
     */
    @Override
    public List<ClassEntity> findByProfessionId(String professionId) {
        return classDao.findByProfessionId(professionId);
    }

    /**
     * 根据专业id查询在校班级以及人员
     *
     * @param majorId
     * @param maxSession
     * @param minSession
     * @param screenClassName
     * @return 班级以及班级人员信息
     * @author 智雪艳
     * @since 2.0.0 2019-05-28 10:35:56
     */
    @Override
    public List<ClassModel> querySchoolClass(String majorId,Object maxSession, Object minSession, String screenClassName) {
        return classDao.querySchoolClass(majorId,maxSession,minSession,screenClassName);
    }

}
